<?php


namespace app\user\controller;


use app\BaseController;
use app\libs\exception\ClientTypeError;
use app\libs\exception\DeleteSuccess;
use app\libs\exception\ForbiddenException;
use app\libs\exception\NotFoundException;
use app\libs\exception\ParamException;
use app\libs\exception\ServerError;
use app\libs\exception\Success;
use app\libs\tool\CacheTool;
use app\libs\tool\QQEmail;
use app\middleware\Auth;
use app\model\DiscussComment;
use app\model\DiscussModel;
use app\model\ImageModel;
use app\model\UserModel;
use app\Request;
use app\user\service\LoginService;
use think\exception\ValidateException;

class Home extends BaseController
{
    protected $middleware = [
      Auth::class => [
          'only' => [
              'getSelf', 'addDiscuss', 'addDiscussComment', 'dleDiscussComment',
              'changeAvatar'
          ]
      ]
    ];

    /**
     * 个人信息
     * @throws NotFoundException
     * @throws ServerError
     */
    public function getSelf(Request $request): \think\response\Json
    {
        $user = (new UserModel())
            ->with(['img'])
            ->find($request->userInfo->user_id);
        return json($user);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     */
    public function setSelf(Request $request)
    {
        $param = $this->request->param(['name', 'sex', 'city', 'github_url', 'profile']);

        $this->verifyParam(
            $param,
            'UserValidate.setSelf'
        );

        $user = (new UserModel())->find($request->userInfo->user_id);

        $user->img_id = $param['img_id'];
        $user->sex = $param['sex'];
        $user->city = $param['city'];
        $user->github_url = $param['github_url'];
        $user->profile = $param['profile'];
        $user->save();
    }

    /**
     * @throws ServerError
     * @throws ParamException
     * @throws ClientTypeError
     * @throws NotFoundException
     * @throws Success
     */
    public function changeAvatar(Request $request)
    {
        try {
            $avatar = $this->request->file('avatar');
        } catch (\Exception $e) {
            throw new NotFoundException(['message' => '没有文件被上传']);
        }

        $this->verifyParam(['avatar' => $avatar], 'UserValidate.avatar');

        $saveName = \think\facade\Filesystem::disk('public')->putFile('topic', $avatar);

        $image = ImageModel::create([
            'url' => $saveName
        ]);

        $user = (new UserModel())->find($request->userInfo->user_id);

        $user->img_id = $image->id;
        $user->save();

        throw new Success(['message' => '头像修改成功']);
    }

    /**
     * @throws NotFoundException
     * @throws \app\libs\exception\ServerError
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws ParamException
     * @throws ClientTypeError
     */
    public function login(): string
    {
        $param = $this->request->param(['email', 'password', 'captcha']);

        // 验证参数
        $this->verifyParam(
            $param,
            'UserValidate.login');

        // 验证邮箱验证码是否正确
        $this->verifyCaptcha($param['captcha'], $param['email']);

        $user = UserModel::where('email', '=', $param['email'])->find();

        if (!$user) throw new NotFoundException(['message' => '用户不存在']);

        if (!$user->check_pwd($param['password'])) throw new ParamException(['message' => '密码错误']);

        return (new LoginService())->save_return_jwt($user->id);
    }

    /**
     * @throws ParamException
     * @throws ServerError
     * @throws ClientTypeError
     * @throws Success
     */
    public function register()
    {
        $param = $this->request->param(['name', 'email', 'password', 'captcha']);

        // 验证参数
        $this->verifyParam(
            $param,
            'UserValidate.register'
        );

        // 验证邮箱验证码是否正确
         $this->verifyCaptcha($param['captcha'], $param['email']);

        // 验证邮箱是否存在
        $this->existEmail($param['email']);

        (new UserModel())->createUser($param);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     * @throws ClientTypeError
     * @throws NotFoundException
     * @throws Success
     */
    public function reset_password()
    {
        $param = $this->request->param(['email', 'password', 'captcha']);

        // 验证参数
        $this->verifyParam(
            $param,
            'UserValidate.reset'
        );

        // 验证邮箱验证码是否正确
        $this->verifyCaptcha($param['captcha'], $param['email']);

        // 验证邮箱是否存在
        $this->existEmail($param['email'], 'reset');

        $user = (new UserModel())
            ->where('email', '=', $param['email'])
            ->find();

        $user->resetPassword($param);

        throw new Success(['message' => '密码修改成功']);
    }

    /**
     * @throws ClientTypeError
     * @throws NotFoundException
     */
    public function existEmail($email, $scene = '')
    {
        $existEmail = UserModel::where('email', '=', $email)->count();
        // 当场景为找回密码的时候, 需要判断邮箱存在 否则不能找回密码
        if ($scene == 'reset' && !$existEmail) throw new NotFoundException(['message' => '邮箱不存在']);
        if ($existEmail && $scene == '') throw new ClientTypeError(['message' => '邮箱已存在']);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     */
    public function verifyParam($param, string $validate, $exception = [])
    {
        if (!$validate) throw new ServerError(['message' => '找不到验证器']);
        try {
            $this->validate($param, $validate);
        } catch (ValidateException $e) {
            $response = ['message' => $e->getMessage()];

            if (array_key_exists('message', $exception)) {
                $response['message'] = $exception['message'];
            }

            if (array_key_exists('code', $exception)) {
                $response['code'] = $exception['code'];
            }

            throw new ParamException($response);
        }
    }

    /**
     * 发送邮箱
     * @throws ServerError
     * @throws ParamException
     * @throws ClientTypeError
     */
    public function sendMailBox(): \think\response\Json
    {
        // 接收参数
        $param = $this->request->param(['name', 'email']);

        // 验证参数
        $this->verifyParam($param, 'UserValidate.sendEmailBox');

        // 如果有名字就需要验证邮箱是否存在  注册情况
        if (array_key_exists('name', $param)) $this->existEmail($param['email']);

        // 发送邮箱
        (new QQEmail())->sendMailtoUser($param['email']);

        return json([
            'code' => 0,
            'message' => '邮箱已发送, 请注意查收'
        ]);
    }

    /**
     * 验证邮箱
     * @throws ClientTypeError
     */
    public function verifyCaptcha($captcha, $email)
    {
        $result = (new CacheTool())->checkCache(config('secure.captcha_key'), $captcha . $email);
        if (gettype($result) === 'string') throw new ClientTypeError(['message' => $result]);
        if (!$result) throw new ClientTypeError(['message' => '验证码错误']);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     */
    public function addDiscuss(Request $request)
    {
        $param = $this->request->param(['title', 'content']);

        $this->verifyParam(
            $param,
            'DiscussValidate.write'
        );

        DiscussModel::create([
            'title' => $param['title'],
            'content' => $param['content'],
            'author_id' => $request->userInfo->user_id
        ]);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     * @throws Success
     */
    public function addDiscussComment(Request $request)
    {
        $param = $this->request->param(['discuss_content', 'discuss_id']);

        $this->verifyParam($param, 'DiscussValidate.common');

        DiscussComment::create([
            'content' => $param['discuss_content'],
            'discuss_id' => $param['discuss_id'],
            'uid' => $request->userInfo->user_id
        ]);

        throw new Success(['message' => '评论成功']);
    }

    /**
     * @throws ServerError
     * @throws ParamException
     * @throws NotFoundException
     * @throws ForbiddenException
     * @throws DeleteSuccess
     */
    public function dleDiscussComment(Request $request)
    {
        $discuss_id = $this->request->param(['discuss_id']);

        $this->verifyParam($discuss_id, 'DiscussValidate.delete_common');

        $discuss_comment = (new DiscussComment())->find($discuss_id);

        if (!$discuss_comment) throw new NotFoundException(['message' => '删除失败, 评论不存在']);

        if ($discuss_comment->uid != $request->userInfo->user_id) {
            throw new ForbiddenException(['message' => '删除失败, 您无法删除他人的评论']);
        }

        $discuss_comment->delete();

        throw new DeleteSuccess();
    }
}